package com.homedo.async.mysql.support.mapper.util;

import com.homedo.async.mysql.support.meta.EntityMetaData;
import com.homedo.plainly.logger.Logger;
import com.homedo.plainly.logger.LoggerFactory;
import io.vertx.mysqlclient.MySQLClient;
import io.vertx.sqlclient.*;
import reactor.core.publisher.Mono;
import reactor.core.publisher.MonoSink;

import java.util.Arrays;
import java.util.List;

/**
 * @author jgshun
 * @date 2020/3/17 12:08 PM
 */
public abstract class CreateMono4PrimaryKeyResultUtil {
    private static final Logger _LOGGER = LoggerFactory.getLogger(CreateMono4PrimaryKeyResultUtil.class);

    public static <T, S> Mono<S> create(Object[] prepareSqlArgs, S entity, EntityMetaData<T> entityMetaData, Pool pool, SqlConnection connection) {

        return Mono.create(sink -> {
            if (connection == null) {
                pool.getConnection(connRes -> {
                    if (connRes.succeeded()) {
                        SqlConnection newConnection = connRes.result();
                        create(prepareSqlArgs, entity, entityMetaData, newConnection, true, sink);
                    } else {
                        sink.error(connRes.cause());
                    }
                });
            } else {
                create(prepareSqlArgs, entity, entityMetaData, connection, false, sink);
            }
        });

    }

    private static <S, T> void create(Object[] prepareSqlArgs, S entity, EntityMetaData<T> entityMetaData, SqlConnection connection, boolean colse, MonoSink<S> sink) {
        connection.preparedQuery(prepareSqlArgs[0].toString(), Tuple.tuple((List<Object>) prepareSqlArgs[1]), res -> {
            if (res.succeeded()) {
                RowSet<Row> rows = res.result();

                if (!entityMetaData.isPrimaryAutoGenerate()) {//主键不用自动生成
                    sink.success(entity);
                    return;
                }

                try {
                    entityMetaData.getPrimaryKeyField().setAccessible(true);
                    if (entityMetaData.getPrimaryKeyField().get(entity) != null) {//手动指定了主键值
                        sink.success(entity);
                        return;
                    }
                } catch (Exception ex) {
                    _LOGGER.error("[获取主键值失败，需要检查错误原因:{},{},{}]", Arrays.asList(prepareSqlArgs), entity, ex.getMessage(), ex);
                    sink.error(ex);
                    return;
                }

                long lastInsertId = rows.property(MySQLClient.LAST_INSERTED_ID);

                entityMetaData.getPrimaryKeyField().setAccessible(true);

                try {
                    if (Long.class.isAssignableFrom(entityMetaData.getPrimaryKeyField().getType())) {
                        entityMetaData.getPrimaryKeyField().set(entity, lastInsertId);
                    } else {
                        entityMetaData.getPrimaryKeyField().set(entity, (int) lastInsertId);
                    }
                } catch (Exception ex) {
                    _LOGGER.error("[设置主键值失败，需要检查错误原因:{},{},{}]", Arrays.asList(prepareSqlArgs), entity, ex.getMessage(), ex);
                    sink.error(ex);
                    return;
                }

                sink.success(entity);

            } else {
                sink.error(res.cause());
                _LOGGER.error("Failure: {}", res.cause().getMessage(), res.cause());
            }

            if (colse) {//释放连接回连接池中
                connection.close();
            }
        });

    }

}
